package com.api.user.service.impl;

import com.api.common.JSONUtils;
import com.api.core.ServiceException;
import com.api.core.response.Result;
import com.api.core.response.ResultGenerator;
import com.api.core.service.AbstractService;
import com.api.user.dao.CommodityMapper;
import com.api.user.model.*;
import com.api.user.service.*;
import com.api.user.vo.CommodityListVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by wanghuiwen on 2021/04/12.
 */
@Service
@Transactional
public class CommodityServiceImpl extends AbstractService<Commodity> implements CommodityService {
    @Resource
    private CommodityMapper commodityMapper;

    @Resource
    private CommodityPictureService commodityPictureService;

    @Resource
    private CommoditySpecsService commoditySpecsService;

    @Resource
    private CouponUserService couponUserService;

    @Resource
    private CouponService couponService;

    @Resource
    private CommodityOrderService commodityOrderService;

    @Resource
    private CommodityOrderTrackService commodityOrderTrackService;

    @Resource
    private OrderCommditysService orderCommditysService;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private PointsTransactionService pointsTransactionService;

    @Resource
    private CoinTransactionService coinTransactionService;

    @Override
    public Result list(Map<String,Object> params, String order, Integer page, Integer size){
//        Map<String, Object> params = JSONUtils.json2map(search);
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
                if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
                if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
            }
        PageHelper.startPage(page, size);
        orderParams.put("commodity_id","desc");
        List<Map<String, Object>> res = commodityMapper.list(params, orderParams);
        for (Map<String, Object> map:res){
            List<CommoditySpecs> commoditySpecs = commoditySpecsService.getByCommodityId((Long) map.get("commodityId"));
            map.put("specs",commoditySpecs);
        }
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }


    @Override
    public Result userList(Map<String,Object> params, String order, Integer page, Integer size){
//        Map<String, Object> params = JSONUtils.json2map(search);
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        PageHelper.startPage(page, size);
        List<CommodityListVo> res = commodityMapper.userList(params, orderParams);
        PageInfo<CommodityListVo> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }


    @Override
    public Result add(CommodityAdd commodityAdd) {
        if(null == commodityAdd.getCommodityId()){
            Commodity commodity = new Commodity();
            commodity.setCategoryId(commodityAdd.getCategoryId());
            commodity.setCommodityIntroduce(commodityAdd.getCommodityIntroduce());
            commodity.setCommodityName(commodityAdd.getCommodityName());
            commodity.setCommodityState(commodityAdd.getCommodityState());
            commodity.setPayMethod(commodityAdd.getPayMethod());
            commodity.setHowUse(commodityAdd.getHowUse());
            commodity.setRule(commodityAdd.getRule());
            commodity.setStandard(commodityAdd.getStandard());
            this.save(commodity);

            String [] urls = commodityAdd.getCommodityPicture().split(",");
            for (int i=0;i<urls.length;i++){
                CommodityPicture commodityPicture = new CommodityPicture();
                commodityPicture.setCommodityId(commodity.getCommodityId());
                commodityPicture.setUrl(urls[i]);
                commodityPictureService.save(commodityPicture);
            }

            for (CommoditySpecs c: commodityAdd.getSpecs()) {
                c.setCommodityId(commodity.getCommodityId());
                commoditySpecsService.save(c);
            }


        }else{
            Commodity commodity = this.findById(commodityAdd.getCommodityId());
            commodity.setCategoryId(commodityAdd.getCategoryId());
            commodity.setCommodityIntroduce(commodityAdd.getCommodityIntroduce());
            commodity.setCommodityName(commodityAdd.getCommodityName());
            commodity.setCommodityState(commodityAdd.getCommodityState());
            commodity.setPayMethod(commodityAdd.getPayMethod());
            this.update(commodity);

            List<CommodityPicture> list = commodityPictureService.getByCommodityId(commodityAdd.getCommodityId());
            for (CommodityPicture c: list) {
                commodityPictureService.deleteById(c.getId());
            }

            String [] urls = commodityAdd.getCommodityPicture().split(",");
            for (int i=0;i<urls.length;i++){
                CommodityPicture commodityPicture = new CommodityPicture();
                commodityPicture.setCommodityId(commodity.getCommodityId());
                commodityPicture.setUrl(urls[i]);
                commodityPictureService.save(commodityPicture);
            }

            List<CommoditySpecs> commoditySpecs = commoditySpecsService.getByCommodityId(commodityAdd.getCommodityId());
            for (CommoditySpecs commoditySpec : commoditySpecs) {
                if(!commodityAdd.getSpecs().stream().anyMatch(spec -> spec.getSpecsId()!=null && spec.getSpecsId().equals(commoditySpec.getSpecsId()))){
                    List<OrderCommditys> commditys = orderCommditysService.getBySepecsId(commoditySpec.getSpecsId());
                    if(!CollectionUtils.isEmpty(commditys)){
                        throw  new ServiceException(commoditySpec.getSpecsName() + " have Order can not delete");
                    }
                    commoditySpecsService.deleteById(commoditySpec.getSpecsId());
                }
            }
            for (CommoditySpecs c: commodityAdd.getSpecs()) {
                if(c.getSpecsId()==null){
                    c.setCommodityId(commodity.getCommodityId());
                    commoditySpecsService.save(c);
                }else {
                    commoditySpecsService.update(c);
                }
            }
        }
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result orderSend(Long orderId,Long userId) {
        CommodityOrder commodityOrder = commodityOrderService.findById(orderId);
        commodityOrder.setOrderState(2);
        commodityOrderService.update(commodityOrder);

        CommodityOrderTrack commodityOrderTrack = new CommodityOrderTrack();
        commodityOrderTrack.setCreateTime(new Date().getTime());
        commodityOrderTrack.setOrderId(orderId);
        commodityOrderTrack.setUserId(userId);
        commodityOrderTrack.setTrackDesc("订单发货");
        commodityOrderTrackService.save(commodityOrderTrack);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result orderBuy(CouponUse couponUse,Long userId) {
        CommodityOrder commodityOrder = new CommodityOrder();
        commodityOrder.setCreateTime(new Date().getTime());
        commodityOrder.setUserId(userId);


        if(null!=couponUse.getCouponCode() && !couponUse.getCouponCode().equals("")){
            CouponUser couponUser = couponUserService.findBy("couponCode",couponUse.getCouponCode());
            if(couponUser.getStatus()){
                return ResultGenerator.genFailResult(400,"Coupon has been used");
            }
            if(couponUser.getValidityTime()<=new Date().getTime()){
                return ResultGenerator.genFailResult(400,"Coupon has expired");
            }
            Coupon coupon = couponService.findById(couponUser.getCouponId());
            if(coupon.getCouponCategory().equals(3)){
                return ResultGenerator.genFailResult(400,"Coupon only applicable to companion");
            }
            if(coupon.getCouponMode()==1 && couponUse.getTotalAmount().compareTo(new BigDecimal(coupon.getCouponMin()))==-1){
                return ResultGenerator.genFailResult(400,"Below the threshold for using coupons");
            }

            commodityOrder.setCouponAmount(coupon.getDenomination());
            commodityOrder.setCouponUserId(couponUser.getCouponUserId());
            couponUser.setStatus(true);
            couponUserService.update(couponUser);

        }
        commodityOrder.setOrderState(1);
        commodityOrderService.save(commodityOrder);



        List<CouponUseCommodity> couponUseCommodities = couponUse.getOrderCommdity();
        BigDecimal total = new BigDecimal(0);
        if(!couponUseCommodities.isEmpty()){
            List<OrderCommditys> orderCommdityss = new ArrayList<>();
            //判断商品的支付方式是否都一样
            CouponUseCommodity cuc0 = couponUseCommodities.get(0);
            CommoditySpecs cs0 = commoditySpecsService.findById(cuc0.getSpecsId());
            Commodity c0 = this.findById(cs0.getCommodityId());
            for(CouponUseCommodity couponUseCommodity:couponUseCommodities){
                commodityOrder.setPayMethod(c0.getPayMethod());
                commodityOrderService.update(commodityOrder);
                CommoditySpecs cs1 = commoditySpecsService.findById(couponUseCommodity.getSpecsId());

                total = total.add(cs1.getSpecsPrice().multiply(new BigDecimal(couponUseCommodity.getAmount())));

                Commodity c1 = this.findById(cs1.getCommodityId());
                if(!c0.getPayMethod().equals(c1.getPayMethod())){
                    throw  new ServiceException("Redemption payment methods cannot be different");
                }
                if(cs1.getSpecsStock() < couponUseCommodity.getAmount()){
                    throw  new ServiceException(cs1.getSpecsName()+"Inventory shortage");
                }
                OrderCommditys orderCommditys = new OrderCommditys();
                orderCommditys.setCommoditySpecsId(couponUseCommodity.getSpecsId());
                orderCommditys.setAmount(couponUseCommodity.getAmount());
                orderCommditys.setOrderId(commodityOrder.getOrderId());
                orderCommdityss.add(orderCommditys);
                //减库存
                cs1.setSpecsStock(cs1.getSpecsStock() - couponUseCommodity.getAmount());
                commoditySpecsService.update(cs1);
            }


            if(commodityOrder.getCouponAmount()!=null){
                if(total.compareTo(commodityOrder.getCouponAmount())<0){
                    throw  new ServiceException("Wrong order amount");
                }
                commodityOrder.setTotalAmount(total.subtract(commodityOrder.getCouponAmount()));
            }else {
                commodityOrder.setTotalAmount(total);
            }
            commodityOrderService.update(commodityOrder);


            if(commodityOrder.getTotalAmount().compareTo(BigDecimal.ZERO) > 0){
                //判断用户余额是否够支付
                UserInfo userInfo = userInfoService.findById(userId);
                if(c0.getPayMethod().equals("point")){
                    if(userInfo.getPoint().compareTo(couponUse.getTotalAmount()) < 0){
                        throw  new ServiceException("Insufficient point");
                    }else{
                        PointsTransaction pointsTransaction = new PointsTransaction();
                        pointsTransaction.setFromUserId(userId);
                        pointsTransaction.setOrderId(commodityOrder.getOrderId());
                        pointsTransaction.setPointAmount(commodityOrder.getTotalAmount());
                        pointsTransaction.setTransactionTime(new Date().getTime());
                        pointsTransaction.setTransactionType(7);
                        pointsTransaction.setRemark("Commodity Order");
                        pointsTransaction.setCreateId(userId);
                        pointsTransactionService.addOrSub(pointsTransaction);
                    }
                }
                else{
                    if(userInfo.getCoin().compareTo(couponUse.getTotalAmount()) < 0){
                        throw  new ServiceException("Insufficient coin");
                    }else{
                        CoinTransaction coinTransaction = new CoinTransaction();
                        coinTransaction.setOrderId(commodityOrder.getOrderId());
                        coinTransaction.setAmountBalance(commodityOrder.getTotalAmount().negate());
                        coinTransaction.setFromUserId(userId);
                        coinTransaction.setTransactionType(7);
                        coinTransaction.setTransactionTime(new Date().getTime());
                        coinTransaction.setRemark("Redemption Order");
                        coinTransaction.setCreateId(userId);
                        coinTransactionService.addOrSub(coinTransaction);
                    }
                }
            }


            for(OrderCommditys o :orderCommdityss){
                orderCommditysService.save(o);
            }
        }

        CommodityOrderTrack commodityOrderTrack = new CommodityOrderTrack();
        commodityOrderTrack.setCreateTime(new Date().getTime());
        commodityOrderTrack.setOrderId(commodityOrder.getOrderId());
        commodityOrderTrack.setUserId(userId);
        commodityOrderTrack.setTrackDesc("Redemption Order");
        commodityOrderTrackService.save(commodityOrderTrack);

        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result stateUpdate(Long commodityId, Integer state) {

        Commodity commodity = this.findById(commodityId);
        commodity.setCommodityState(state);
        update(commodity);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result detail(Long commodityId) {
        CommodityListVo vo = commodityMapper.detail(commodityId);
        return ResultGenerator.genSuccessResult(vo);
    }
}
